#include <jni.h>
#include <string>
#include <assert.h>
#include <stdlib.h>
#include <ctype.h>


#include "native-lib.h"  //引入头文件.
//#include "AndroidDef/vm/Common.h"
#include "AndroidDef/vm/oo/Object.h"
#include "hongbao/hongbao.h"
#include "AndroidDef/AndroidDef.h"

#include "asm-generic/mman-common.h"
#include "sys/mman.h"
#include "limits.h"

const char insns[] = {0x12,0x30,0x0f,0x00};

void* get_module_base(pid_t pid,const char* module_name);

//参数映射表
//这是在MainActivity中的native方法
static JNINativeMethod gMethods_MainActivity[] = {
        {"stringFromJNI", "()Ljava/lang/String;",                   (void *) stringFromJNI},
        {"setString",     "(Ljava/lang/String;)Ljava/lang/String;", (void *) setString},
        {"chgM",     "(Ljava/lang/reflect/Method;)V", (void *) chgM},
        {"chgM2",     "()V", (void *) chgM2},
};


//实现在MainActivity类的两个方法stringFromJNI()    setString()
static jstring stringFromJNI(JNIEnv *env, jobject obj) {
    return env->NewStringUTF("欢迎来到jin的世界...");
}

jstring setString(JNIEnv *env, jobject instance, jstring str_) {
    return str_;
}

void chgM(JNIEnv *env, jobject instance, jobject method) {
    Method* method1 = (Method*)env->FromReflectedMethod(method);
    method1->insns = (const u2 * )insns;
}

void chgM2(JNIEnv *env, jobject instance) {
    u1 *pDex = (u1 *) get_module_base(-1,"/data/dalvik-cache/data@app@com.lb.dtregister");
    if(pDex !=NULL)
    {
        LOGD("Get Module");
        pDex += sizeof(DexOptHeader);
        DexFile *pDexFile = dexFileParse(pDex,0xB4000,kDexParseContinueOnError);
        if(pDexFile == NULL)
        {
            LOGE("Unable to parse DxFile");
            return ;
        }
        const DexClassDef *pClassDef ;
        for (int i=0 ; i<pDexFile -> pHeader->classDefsSize ; ++i )
        {
            const DexClassDef *pDef = dexGetClassDef(pDexFile,i);
            if(!strcmp(dexStringByTypeIdx(pDexFile,pDef->classIdx),"com/lb/dtregister/MainActivity;"))
            {
                pClassDef = pDef ;
                break;
            }
        }

        if(pClassDef != NULL)
        {
            LOGD("Class Found!!!");
            const u1 *pData = dexGetClassData(pDexFile,pClassDef);
            if(pData)
            {
                DexClassData *pClassData = dexReadAndVerifyClassData(&pData,NULL);
                for(int i = 0;i<pClassData->header.virtualMethodsSize;++i)
                {
                    DexMethod *pMethod = &pClassData->virtualMethods[i] ;
                    const DexMethodId *pMethodId = dexGetMethodId(pDexFile,pMethod->methodIdx);
                    if(!strcmp(dexStringById(pDexFile,pMethod->methodIdx),"ret1"))
                    {
                        const DexCode *pCode = dexGetCode(pDexFile,pMethod);
                        LOGD("METHOD found try to pathch");
                        if(mprotect((void*)PAGE_START((long)pCode->insns),PAGE_SIZE,PROT_READ|PROT_WRITE) == 0)
                        {
                            *((u4*)(pCode->insns)) = 0x000f2012;
                            mprotect((void*)PAGE_START((long)pCode->insns),PAGE_SIZE,PROT_READ);
                        }
                    }

                }
                free(pClassData);
            }
        }

        dexFileFree(pDexFile);
    }
}

void* get_module_base(pid_t pid,const char* module_name)
{
    FILE *fp;
    long addr = 0 ;
    char *pch ;
    char filename[32];
    char line[1024];
    if(pid < 0) {
        snprintf(filename, sizeof(filename), "/proc/self/maps");
    } else{
        snprintf(filename,sizeof(filename),"/proc/%d/maps",pid);
    }

    fp = fopen(filename,"r");
    if(fp != NULL)
    {
        while(fgets(line,sizeof(line),fp))
        {
            //LOGD(line);
            if(strstr(line,module_name)){
                pch = strtok (line ,"-");
                addr = strtoul(pch,NULL,16);
                break;
            }
        }
        fclose(fp);
    }

    return  (void *) addr;

}

//找到MainActivity.java类
static int registerNatives(JNIEnv *engv) {
    jclass clazz;
    clazz = engv->FindClass("com/lb/dtregister/MainActivity");   //找到MainActivity类
    if (clazz == NULL) {
        return JNI_FALSE;
    }
    //int len = sizeof(methods) / sizeof(methods[0]);
    if (engv->RegisterNatives(clazz, gMethods_MainActivity,
                              sizeof(gMethods_MainActivity) / sizeof(gMethods_MainActivity[0])) <
        0) {
        return JNI_FALSE;
    }
    return JNI_TRUE;
}

/*//注册 HongBao 中的native方法
static int registerNatives_HongBao(JNIEnv *engv) {
    jclass clazz;
    clazz = engv->FindClass("com/lb/dtregister/HongBao");    //找到HongBao类

    if (clazz == NULL) {
        return JNI_FALSE;
    }
    if (engv->RegisterNatives(clazz, gMethods_HongBao,
                              sizeof(gMethods_HongBao) / sizeof(gMethods_HongBao[0])) < 0) {
        return JNI_FALSE;
    }
    return JNI_TRUE;
}*/

JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) {
    JNIEnv *env = NULL;
    jint result = -1;
    if (vm->GetEnv((void **) &env, JNI_VERSION_1_6) != JNI_OK) {
        return result;
    }
    assert(env != NULL);
    //为了方便管理我们将不同java类中的native方法分别注册
    if (registerNatives(env) < 0) {  //注册HongBao类的native方法
        return result;
    }
    if (registerNatives_HongBao(env) < 0) {  //注册MainActivity类的native方法
        return result;
    }
    return JNI_VERSION_1_6;
}



